package pl.wroc.uni.ii.pastuszka.algorithms.evolutionary.genetic;

import java.util.Collections;

import pl.wroc.uni.ii.pastuszka.algorithms.evolutionary.Individual;
import pl.wroc.uni.ii.pastuszka.algorithms.evolutionary.utils.BinaryRandom;

public class SSGA extends GeneticAlgorithmSchema {

  private int individualsToKill;

  public void setIndividualsToKill(int individualsToKill) {
    this.individualsToKill = individualsToKill;
  }

  public SSGA() {
  }

  public SSGA(int chromosomeLength, int populationSize, int individualsToKill) {
    super(chromosomeLength, populationSize);
    setIndividualsToKill(individualsToKill);
  }

  private void killWorstIndividuals() {
    Collections.sort(population, Individual.RANK_COMPARATOR);

    for (int i = 0; i < individualsToKill; ++i) {
      Individual goodIndividual = population.get(populationSize - individualsToKill + i);
      Individual cloneOfGoodIndividual = new Individual(goodIndividual);
      population.set(i, cloneOfGoodIndividual);
    }
  }

  private void breed() {
    Collections.shuffle(population);

    for (int i = 0; i < populationSize / 2; ++i) {
      Individual mother = population.get(2 * i);
      Individual father = population.get(2 * i + 1);
      crossoverGenes(mother, father);
    }
  }

  private void crossoverGenes(Individual mother, Individual father) {
    for (int j = 0; j < chromosomeLength; ++j) {
      if (BinaryRandom.getBoolean()) {
        swapGene(mother, father, j);
      }
    }
  }

  private void swapGene(Individual mother, Individual father, int j) {
    int fatherGene = father.chromosome[j];
    father.chromosome[j] = mother.chromosome[j];
    mother.chromosome[j] = fatherGene;
  }

  @Override
  protected void applyGeneticOperators() {
    killWorstIndividuals();
    breed();
  }

}
